#include <pthread.h>
#include <queue>
#include <semaphore.h>

using namespace std;

template <class T>
class RingQueue 
{
private:
    static const int defaultcap = 5;
    
    void P(sem_t &sem)  //--
    {
        sem_wait(&sem);    //申请信号量，当信号量不足的时候，会阻塞
    }

    void V(sem_t &sem)  //++
    {
        sem_post(&sem);
    }

    void Lock(pthread_mutex_t &mutex)
    {
        pthread_mutex_lock(&mutex);
    }

    void Unlock(pthread_mutex_t &mutex)
    {
        pthread_mutex_unlock(&mutex);
    }

public:
    RingQueue(int cap = defaultcap)
    : _cap(cap)
    , _Cidx(0)
    , _Pidx(0)
    ,_Pmutex(PTHREAD_MUTEX_INITIALIZER)
    ,_Cmutex(PTHREAD_MUTEX_INITIALIZER)
    {
        sem_init(&_Csem, 0, 0);     //pshared:0表示线程间共享，非零表示进程间共享 value：信号量初始值
        sem_init(&_Psem, 0, _cap);
    }

    void Push(const T& val)
    {
        P(_Psem);       //生产者信号量--
        Lock(_Pmutex);   //生产者互斥锁
       
        //生产者生产数据
        _ringqueue[_Pidx] = val;

        // 位置后移，维持环形特性
        _Pidx++；   //生产者下标++
        _Pidx %= _cap;

        Unlock(_Pmutex);  
        V(_Csem);    //全部完成之后，消费者信号量++
    }

    T Pop(T* out)   //输出型参数
    {
        P(_Csem);    
        Lock(_Cmutex);

        //消费者消费数据
        *out = _ringqueue[_Cidx];

        // 位置后移，维持环形特性
        _Cidx++;
        _Cidx %= _cap;

        Unlock(_Cmutex);
        V(_Psem);
    }


    ~RingQueue()
    {
        sem_destroy(&_Csem);
        sem_destroy(&_Psem);
    }
    
private:
    int _cap;
    vector<T> _ringqueue;

    //生产消费的下标
    int _Cidx;
    int _Pidx;

    //信号量
    sem_t _Csem;    //消费者信号量（虽然是计数器，但是是一个自定义类型）
    sem_t _Psem;
    pthread_mutex_t _Pmutex;    //生产者互斥锁
    pthread_mutex_t _Cmutex;    //消费者互斥锁
};